package prompts

import (
	"fmt"
	"strings"
)

// PromptTemplate represents a template for generating prompts
type PromptTemplate struct {
	Name        string                 // template name
	Description string                 // template description
	Template    string                 // template content with placeholders
	Variables   []string               // list of required variables
	Defaults    map[string]string      // default values for variables
	Examples    []map[string]string    // example variable values
	Metadata    map[string]interface{} // additional metadata
}

// PromptResult represents the result of prompt generation
type PromptResult struct {
	Template *PromptTemplate        // template used
	Input    map[string]interface{} // input variables
	Output   string                 // generated prompt
	Metadata map[string]interface{} // additional metadata
}

// PromptManager manages prompt templates
type PromptManager struct {
	templates map[string]*PromptTemplate
}

// NewPromptManager creates a new prompt manager
func NewPromptManager() *PromptManager {
	return &PromptManager{
		templates: make(map[string]*PromptTemplate),
	}
}

// RegisterTemplate registers a new prompt template
func (m *PromptManager) RegisterTemplate(template *PromptTemplate) error {
	if template.Name == "" {
		return fmt.Errorf("template name is required")
	}

	// Validate template variables
	for _, v := range template.Variables {
		if !strings.Contains(template.Template, "{{"+v+"}}") {
			return fmt.Errorf("template missing variable: %s", v)
		}
	}

	m.templates[template.Name] = template
	return nil
}

// GetTemplate gets a template by name
func (m *PromptManager) GetTemplate(name string) *PromptTemplate {
	return m.templates[name]
}

// ListTemplates lists all available templates
func (m *PromptManager) ListTemplates() []*PromptTemplate {
	templates := make([]*PromptTemplate, 0, len(m.templates))
	for _, tmpl := range m.templates {
		templates = append(templates, tmpl)
	}
	return templates
}

// GeneratePrompt generates a prompt using a template
func (m *PromptManager) GeneratePrompt(templateName string, variables map[string]interface{}) (*PromptResult, error) {
	template := m.GetTemplate(templateName)
	if template == nil {
		return nil, fmt.Errorf("template not found: %s", templateName)
	}

	// Replace variables in template
	result := template.Template
	for key, value := range variables {
		result = strings.ReplaceAll(result, "{{"+key+"}}", fmt.Sprintf("%v", value))
	}

	return &PromptResult{
		Template: template,
		Input:    variables,
		Output:   result,
		Metadata: make(map[string]interface{}),
	}, nil
}

// Common prompt templates
var (
	DefaultSystemPrompt = &PromptTemplate{
		Name:        "system",
		Description: "Default system prompt template",
		Template: `You are an AI assistant with the following capabilities:
{{- range .Capabilities}}
- {{.}}
{{- end}}

Your task is to {{.Task}}

Please follow these guidelines:
{{- range .Guidelines}}
- {{.}}
{{- end}}`,
		Variables: []string{"Capabilities", "Task", "Guidelines"},
	}

	CodeGenerationPrompt = &PromptTemplate{
		Name:        "code_generation",
		Description: "Template for code generation tasks",
		Template: `Generate {{.Language}} code that satisfies the following requirements:

Requirements:
{{.Requirements}}

Additional context:
{{.Context}}

Please ensure the code:
- Is well-documented
- Follows best practices
- Is efficient and maintainable
- Includes error handling
- Has proper input validation

The code should be complete and ready to use.`,
		Variables: []string{"Language", "Requirements", "Context"},
	}

	CodeAnalysisPrompt = &PromptTemplate{
		Name:        "code_analysis",
		Description: "Template for code analysis tasks",
		Template: `Analyze the following {{.Language}} code:

'''{{.Language}}
{{.Code}}
'''

Focus on:
{{- range .Aspects}}
- {{.}}
{{- end}}

Provide:
1. A brief overview of what the code does
2. Potential issues or improvements
3. Suggestions for better practices
4. Any security concerns
5. Performance considerations`,
		Variables: []string{"Language", "Code", "Aspects"},
	}
)

// NewPromptTemplate creates a new prompt template
func NewPromptTemplate(text string, Variables []string) (*PromptTemplate, error) {
	tmpl := &PromptTemplate{
		Template:  text,
		Variables: Variables,
	}
	return tmpl, nil
}

// RenderPrompt renders the template with given variables
func (p *PromptTemplate) RenderPrompt(vars map[string]string) (string, error) {
	result := p.Template
	for key, value := range vars {
		result = strings.ReplaceAll(result, "{{"+key+"}}", value)
	}
	return result, nil
}
